package beanstao.util.threads;

/**
 * Extend this class to create a thread that can be paused, resumed and canceled. For an example check the source of the
 * FileThread class.
 */
public abstract class AbstractPauseThread extends Thread implements IPauseThread
{
	private static int NORMAL = 0;
	private static int PAUSE = 1;
	private static int RESUME = 2;

	private int request;

	/**
	 * Constructs a IPauseThread without setting the name.
	 */
	public AbstractPauseThread()
	{
		this("Pause Thread");
		request = NORMAL;
	}

	/**
	 * Constructs a IPauseThread with the given name.
	 * @param name Pause Thread name
	 */
	public AbstractPauseThread(String name)
	{
		super(name);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.pausethread.Pause#cancelWork()
	 */
	public final synchronized void cancelWork()
	{
		this.interrupt();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.pausethread.Pause#pauseWork()
	 */
	public final synchronized void pauseWork()
	{
		request = PAUSE;
		this.notify();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.pausethread.Pause#resumeWork()
	 */
	public final synchronized void resumeWork()
	{
		if (request == PAUSE)
		{
			request = RESUME;
			this.notify();
		}
	}

	/**
	 * Calling this method will pause the thread if a pause has been requested by calling the pauseWork() method. The thread
	 * will pause until resumeWork() is called.
	 * @throws InterruptedException thrown if the cancelWork() is called
	 */
	protected final void waitIfPauseRequest() throws InterruptedException
	{
		synchronized (this)
		{
			if (this.isInterrupted())
				throw new InterruptedException("Thread has been stopped.");
			else if (request == PAUSE)
			{
				while (request != RESUME)
					this.wait();
				request = NORMAL;
			}
		}
	}

	/**
	 * This method invokes threadRun(). If cancelWork() is called threadStopped() is invoked.
	 */
	@Override
	public final void run()
	{
		try
		{
			this.doWork();
			this.workDone();
		}
		catch (InterruptedException e)
		{
			this.workCanceled();
		}
	}

	/**
	 * Implement this method to do the actual work. waitIfPauseRequest() has to be called repeatingly so the thread will pause
	 * if a pause has been requested.
	 */
	public abstract void doWork() throws InterruptedException;

	/**
	 * This method is invoked after doWork() has returned. Cleaning up any resources used should be done in this method.
	 */
	public abstract void workDone();

	/**
	 * This method is invoked after cancelWork() has been invoked. Cleaning up any resources used should be done in this method.
	 */
	public abstract void workCanceled();
}
